  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <unistd.h>
  #include <sys/types.h>
  #include <sys/wait.h>
  
  
  
  #define SIZE 1024
  #define MAX_ARGV 64
  #define SEP " "
  
  
  //命令行参数表
  char* argv[MAX_ARGV];
  char pwd[SIZE];
  char env[SIZE];
  int lastcode=0;
  
  
  
  
  
  const char* HostName()
  {
    char *hostname=getenv("HOSTNAME");
      
      if(hostname)  return hostname;    
        else return "None";    
          
  }    
      
      
  const char* UserName()    
  {    
    char *hostname=getenv("USER");    
                                                                                        
      if(hostname)  return hostname;    
        else return "None";    
  }        


const char* CurrentWorkDir()
  {
    char *hostname=getenv("PWD");
  
      if(hostname)  return hostname;                                                    
        else return "None";
  }    
  
  
  char* Home()
  {
    return getenv("HOME");
  }
  
  
  
  int Interactive(char out[],int size)
  {
      
  //[zl@hcss-ecs-9b79 shell]$
     printf("\033[31m[%s@%s %s]$\033[0m",UserName(),HostName(),CurrentWorkDir());
  
      //获取命令字符串
      fgets(out,size,stdin);
  
      out[strlen(out)-1]=0;//空串下'\0'
  
      return strlen(out);
  }


 void Splist(char in[])
  {
    int i=0;
     argv[i++]=strtok(in,SEP);
                                                                                        
     //strtok如果失败返回null
     //命令行参数表以null结尾
  while(argv[i++]=strtok(NULL,SEP));
   
     //让ls带上颜色
     if(strcmp(argv[0],"ls")==0)
     {
       argv[i-1]=(char*)"--color";
       argv[i]=NULL;
     }
  }
  
  int BuildinCmd()
  {
    int ret=0;
     
    //检测是否是内建命令
    //实现只能穷举
    if(strcmp("cd",argv[0])==0)
    {
      //执行
      ret=1;
      char* target=argv[1];
      //cd 后什么都不跟返回家目录
       if(!target)target=Home();
       
       //改变进程的当前工作目录
       chdir(target);

       char temp[SIZE];
       //获取当前进程工作目录
       getcwd(temp,1024);
       //存入pwd缓冲区
       snprintf(pwd,SIZE,"PWD=%s",temp);
       //将PWD环境变量设置为pwd缓冲区中的内容
       putenv(pwd);
    }
    else if(strcmp("export",argv[0])==0)
    {
      ret=1;
           
       if(argv[1])
       {
         strcpy(env,argv[1]);
         putenv(env);
       }

    }
    else if (strcmp("echo",argv[0])==0)
    {
          ret=1;

          if(argv[1]==NULL)
            printf("\n");
          else{
             //echo $? 获取上次进程退出状态
            if(argv[1][0]=='$')
            {
                 if(argv[1][1]=='?')
                 {
                   printf("%d\n",lastcode);
                   lastcode=0;

                 }
                 else{
                    char* e=getenv(argv[1]+1);
                    if(e)
                      printf("%s\n",e);
                 }


            }
            else{
              printf("%s\n",argv[1]);
            }
            
                

          }

    }


    return  ret;
  
      
}
  


  void Execute()
  {
    pid_t id=fork();
  
                                                                                        
    if(id==0)
    {
      //子进程执行命令
      //程序替换
      execvp(argv[0],argv);
      exit(1);
    }
  
    //父进程阻塞等待
    int status=0;
      //成功返回子进程pid
    pid_t rid=waitpid(id,&status,0);
    //获取子进程退出状态
     if(rid==id)
      lastcode=WEXITSTATUS(status);
  }
  
  
  int main()
  {
    while(1){
    
    //1 打印命令提示符，并且获取用户输入命令字符串
           char commandline[SIZE];
  
           int n=Interactive(commandline,SIZE);
     //2 对命令字符串切割
     Splist(commandline);
     
     //3 处理内建命令
    n=BuildinCmd();
    if(n) continue;
  
     //4 执行命令
     Execute();
    }
        return 0;
  }
  



